package com.facebook.buck_project_builder.targets;

import com.facebook.buck_project_builder.CommandLine;
import com.facebook.buck_project_builder.SimpleLogger;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.util.concurrent.TimeUnit;

public final class GeneratedBuildRuleRunner {

  private GeneratedBuildRuleRunner() {}

  static @Nullable ImmutableList<String> buildSources(
      @Nullable String cellPath, String buckRoot, String basePath, JsonArray sourcesField) {
    ImmutableList.Builder<String> sourcesBuilder = ImmutableList.builder();
    for (JsonElement sourceElement : sourcesField.getAsJsonArray()) {
      String source = sourceElement.getAsString();
      if (source.startsWith("//") || source.startsWith(":")) {
        // If a source refers to a buck target, it's likely that it's generated by some
        // custom rules, which we cannot support due to its performance cost.
        return null;
      }
      sourcesBuilder.add(Paths.get(cellPath != null ? cellPath : buckRoot, basePath, source).toString());
    }
    return sourcesBuilder.build();
  }

  static boolean runBuilderCommand(String builderCommand, String buckRoot) throws IOException {
    @Nullable File outputFile = null;
    try {
      outputFile = File.createTempFile("temp", null);
      if (outputFile != null) {
        outputFile.deleteOnExit();
      }
      Process process =
        new ProcessBuilder()
        .command(org.apache.commons.exec.CommandLine.parse(builderCommand).toStrings())
        .redirectError(ProcessBuilder.Redirect.INHERIT)
        .redirectOutput(ProcessBuilder.Redirect.to(outputFile))
        .directory(new File(buckRoot))
        .start();
      boolean hasTimedOut = !process.waitFor(60, TimeUnit.SECONDS);
      if (hasTimedOut) {
        return false;
      }
      return process.exitValue() == 0;
    } catch (IOException | InterruptedException exception) {
      if (outputFile != null) {
        String output = new String(Files.readAllBytes(outputFile.toPath()));
        output = exception.getMessage() + output;
        throw new IOException(output);
      }
      throw new IOException(exception.getMessage());
    }
  }

  public static @Nullable String getBuiltTargetExecutable(String builderTarget, String buckRoot)
      throws IOException {
    try (InputStream inputStream =
        CommandLine.getCommandLineOutput(
            new File(buckRoot), "buck", "build", "@mode/opt", "--show-json-output", builderTarget)) {
      JsonElement builtOutputElement =
          new JsonParser()
              .parse(new InputStreamReader(inputStream))
              .getAsJsonObject()
              .get(builderTarget);
      return builtOutputElement == null ? null : builtOutputElement.getAsString();
    }
  }
}
